package cn.wps.moffice.framework.thread;

import android.os.Handler;
import android.os.Looper;

public final class KThread implements Runnable {

	static final boolean DEBUG = false; //DebugConfig.DEBUG;
	
	volatile int _index;
	volatile boolean _droped;
	
	private Handler mHandler;
	
	private volatile boolean mIsQuiting;
	
	private static final int STARTED = 1 << 0;
	private static final int WORKING = 1 << 2;
	private static final int QUITED  = 1 << 4;
	private volatile int mStatus;
	
	private Thread mThead = new Thread(this, "KThread");
	
	final public Handler getHandler()
	{
		return mHandler;
	}
	
	final public boolean isQuiting()
	{
		return mIsQuiting;
	}
	
	final public void recycle()
	{
		// reset thread name
//		mThead.setName("");
		KThreadPool.joinThreadPool(this);
	}

	private KThread()
	{

	}
	
	static KThread createThread()
	{
		KThread thr = new KThread();
		thr.mThead.start();
		
		synchronized (thr) {
            while (!((thr.mStatus & STARTED) == STARTED)) {
                try {
                    thr.wait();
                } catch (InterruptedException e) {
                }
            }
        }
		
		return thr;
	}
	
	final void waitQuit()
	{
		synchronized (this) {
			while (!((mStatus & QUITED) == QUITED)) {
                try {
                	wait();
                } catch (InterruptedException e) {
                }
            }
		}
	}
	
	final boolean isQuited()
	{
		return (mStatus & QUITED) == QUITED;
	}
	
	public final void waitWorkDone()
	{
		synchronized (this) {
			while ((mStatus & WORKING) == WORKING) {
                try {
                	wait();
                } catch (InterruptedException e) {
                }
            }
		}
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Thread#run()
	 * 
	 */
	@Override
	final public void run() {
		Looper.prepare();

		mHandler = new Handler();
		
		synchronized (this) {
			mStatus |= STARTED;
            notifyAll();
        }
		
		Looper.loop();
		
		synchronized (this) {
            mStatus |= QUITED;
            notifyAll();
        }
	}
	
	final void quit()
	{
		quit(false);
	}
	
	final void quit(boolean mayInterruptIfRunning)
	{
		if (isQuiting())
		{
//			KLog.warning(TAG, "quit: quit more than once");
			return;
		}
		mIsQuiting = true;
		mHandler.post(new Runnable() {
			public void run() {
				Looper.myLooper().quit();
			}
		});
		if (mayInterruptIfRunning)
		{
			interrupt();
		}
	}
	
	public final void interrupt()
	{
		mThead.interrupt();
	}
	
	private void innerExecute(Runnable runnable)
	{
		innerExecute(runnable, 0);
	}
	
	private void innerExecute(Runnable runnable, long delayTime)
	{
		// 对mIsQuiting的检测并不是线程同步的，就是说可能会在quit消息之后再post runnable;
		// 这里的检测并不能防止此类错误，只是最大可能给出log提示;
		// 但这并不会出错，原因是quit之后，Looper就不会再对消息队列进行处理了，
		// post的runnable并不会被执行，就如这里的逻辑一样。
		if (isQuiting())
		{
//			KLog.warning(TAG, "innerExecute: thread is quiting");
			return;
		}
		if (delayTime > 0)
		{
			mHandler.postDelayed(runnable, delayTime);
		}
		else
		{
			mHandler.post(runnable);
		}
	}
	
	private class RunnableWraper implements Runnable
	{
		private final Runnable mRunnable;
		private final boolean mRecycle;
		
		RunnableWraper(Runnable runnable, boolean recycle)
		{
			mRunnable = runnable;
			mRecycle = recycle;
		}
		
		@Override
		public void run() {
			
			synchronized (KThread.this) {
				mStatus |= WORKING;
				KThread.this.notifyAll();
	        }
			
			try {
				mRunnable.run();
			}
			catch (Throwable e)
			{
				e.printStackTrace();
			}

			synchronized (KThread.this) {
				mStatus &= ~WORKING;
				KThread.this.notifyAll();
	        }
			
			if (mRecycle)
			{
				recycle();
			}
		}
	}
	
	public final void execute(Runnable runnable)
	{
		innerExecute(new RunnableWraper(runnable, false));
	}
	
	final void autoJoinExecute(Runnable runnable)
	{
		autoJoinExecute(runnable, 0);
	}
	
	public void setName(final String name)
	{
		if (null == name)
		{
			// bug 198233
			mThead.setName("");
		}
		else
		{
			mThead.setName(name);
		}
	}
	final void autoJoinExecute(Runnable runnable, long delayTime)
	{
		innerExecute(new RunnableWraper(runnable, true), delayTime);
	}
	
	///////////////////////////////////////////////////////////////////////
	public static KThread obtain()
	{
		return KThreadPool.obtainThread();
	}
	
	public static void threadExecute(Runnable runnable)
	{
		threadExecute(runnable, 0);
	}
	
	public static void threadExecute(Runnable runnable, long delayTime)
	{
		KThreadPool.threadExecute(runnable, delayTime);
	}
	
	public static void sleep(int time) throws InterruptedException
	{
		Thread.sleep(time);
	}

	public static void sleep(long millis, int nanos) throws InterruptedException {
		Thread.sleep(millis, nanos);
    }
}
